#include "ReadFile.hpp"
#include <Windows.h>

namespace ge {

//----------------------------------------------------------------------------//
// ReadFile
//----------------------------------------------------------------------------//

//----------------------------------------------------------------------------//
ReadFile::ReadFile( void ) : m_handle( 0 ), m_buffer_pos( 0 ), m_buffer_size( 0 )
{
}
//----------------------------------------------------------------------------//
ReadFile::~ReadFile( void )
{
     if( m_handle ) CloseHandle( m_handle );
}
//----------------------------------------------------------------------------//
uint ReadFile::Read( void* _dst, uint _size )
{
     if( m_pos + _size > m_size ) _size = m_size - m_pos;
     if( !_dst || !_size ) return 0;
     if( m_pos >= m_buffer_pos && m_pos + _size <= m_buffer_pos + m_buffer_size )
     {
      $_read_from_buffer:

          memcpy( _dst, m_buffer + ( m_buffer_pos - m_pos ), _size );
     }
     else if( _size < Threshold ) // reload buffer
     {
          m_buffer_size = Min<uint>( m_size - m_pos, BufferSize );
          m_buffer_pos = m_pos;
          _ReadFrom_Impl( m_buffer_pos, m_buffer, m_buffer_size );
          goto $_read_from_buffer;
     }
     else 
     {
          _ReadFrom_Impl( m_pos, _dst, _size );
     }
     
     m_pos += _size;
     return _size;
}
//----------------------------------------------------------------------------//
uint ReadFile::ReadFrom( uint _offset, void* _dst, uint _size )
{
     if( _offset > m_size ) _offset = m_size;
     if( _offset + _size > m_size ) _size = m_size - _offset;
     if( !_size || !_dst ) return 0;
     _ReadFrom_Impl( _offset, _dst, _size );
     return _size;
}
//----------------------------------------------------------------------------//
void ReadFile::_Open( const String& _path )
{
     assert( m_handle == 0 );
                                                                                                     
     m_handle = (void*)CreateFileA( m_name = _path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
     geAssertT( IOError, m_handle != 0, "ReadFile - Could not open file \"%s\", (Win32Error = %d)", m_name.Data(), GetLastError() );
     m_size = GetFileSize( (HANDLE)m_handle, 0 );
}
//----------------------------------------------------------------------------//
void ReadFile::_ApplyPos( void )
{
     // do nothing    
}
//----------------------------------------------------------------------------//
void ReadFile::_ReadFrom_Impl( uint _offset, void* _dst, uint _size )
{
     DWORD _readed;
     OVERLAPPED _pos = { 0,0,_offset, 0,0 };
     ::ReadFile( m_handle, _dst, _size, &_readed, &_pos );
}
//----------------------------------------------------------------------------//

//----------------------------------------------------------------------------//
//
//----------------------------------------------------------------------------//

} // namespace ge
